package com.shiliao.framework.network;

import android.content.Context;
import android.widget.ImageView;

import com.alibaba.fastjson.JSON;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import com.shiliao.framework.FrameworkConfig;
import com.shiliao.framework.util.LogUtil;
import com.shiliao.framework.util.StringUtil;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


/**
 * Created by yjl on 2017/6/10.
 */

public class OkhttpManager extends BaseNetWork {

    private static final MediaType TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType TYPE_FORM = MediaType.parse("text/html; charset=utf-8");
    private static final MediaType YPE_PNG = MediaType.parse("image/jpg");
    private OkHttpClient mClient;
    private static OkhttpManager okhttpManager;
    private Picasso picasso;
    private OkHttpDownLoader okHttpDownLoader;

    public OkhttpManager() {
        if (mClient == null) {
            mClient = new
                    OkHttpClient.Builder().
                    addNetworkInterceptor(new MInterceptor())
                    .cache(new Cache(new File(FrameworkConfig.pmImageDir), 1024 * 1024 * 100))
                    .build();
        }
    }

    public static synchronized OkhttpManager getInstance() {
        if (okhttpManager == null) {
            okhttpManager = new OkhttpManager();
        }
        return okhttpManager;
    }

    /**
     * 带参数的异步get请求
     *
     * @param url
     * @param params
     * @param mCallBack
     * @throws Exception
     */
    public void loadDataByGet(String url, Map params, final ICallBack mCallBack) throws Exception {
        loadDataByGet(propertURLStr(url, params), mCallBack);
    }

    @Override
    public void loadDataByGet(String url, final ICallBack mCallBack) throws Exception {
        if (!StringUtil.isUrl(url)) {
            if (mCallBack != null) {
                LogUtil.e(url + " url is not available!");
                mCallBack.onFail(404, url + "url is not available!");
            }
            return;
        }
        Request request = new Request.Builder().url(url).build();
        Call call = mClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.e("yjl", "onFailure:" + e.getMessage());
                if (mCallBack != null) {
                    mCallBack.onFail(100000, e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                if (response.isSuccessful()) {
                    if (response.body() != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }

                    }
                } else {
                    if (response != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {

                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }
                    }
                    //throw new IOException("Unexpected code " + response);
                }

                LogUtil.e("onResponse:" + response.message());
            }
        });
    }


    @Override
    public void loadDataByPost(String url, String json, final ICallBack mCallBack) throws Exception {
        //RequestBody body = RequestBody.create(TYPE_JSON, json);
        if (!StringUtil.isUrl(url)) {
            LogUtil.e(url + " url is not available!");
            if (mCallBack != null) {
                mCallBack.onFail(404, url + "url is not available!");
            }
            return;
        }
        FormBody.Builder builder = new FormBody.Builder();
        if (json != null) {
            Map map = JSON.parseObject(json, Map.class);
            Iterator it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
                builder.add("" + entry.getKey(), "" + entry.getValue());
            }
        }

        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        Call call = mClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.e("yjl", "onFailure:" + e.getMessage());
                if (mCallBack != null) {
                    mCallBack.onFail(100000, e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                if (response.isSuccessful()) {
                    if (response.body() != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }

                    }
                } else {
                    if (response != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }
                    }
                }

                LogUtil.e("onResponse:" + response.message());
            }
        });
    }

    @Override
    public void loadDataByPost(final String url, Map param, final ICallBack mCallBack) throws Exception {
        LogUtil.d("url:" + url);
        LogUtil.d("param:" + param);
        if (!StringUtil.isUrl(url)) {
            if (mCallBack != null) {
                LogUtil.e(url + " url is not available!");
                mCallBack.onFail(404, url + "url is not available!");
            }
            return;
        }
        FormBody.Builder builder = new FormBody.Builder();
        //Map map = JSON.parseObject(json, Map.class);
        if (param != null) {
            Iterator it = param.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
                builder.add("" + entry.getKey(), "" + entry.getValue());
            }
        }

        final Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        Call call = mClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.e("yjl", "onFailure:" + e.getMessage());
                if (mCallBack != null) {
                    mCallBack.onFail(100000, e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                LogUtil.e("onResponse:" + response.message());
                if (response.isSuccessful()) {
                    if (response.body() != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }
                    }
                } else {
                    if (response != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    /**
     * 头像上传
     *
     * @param url
     * @param param
     * @param mCallBack
     * @throws Exception
     */
    @Override
    public void postPic(String url, Map param, final ICallBack mCallBack) throws Exception {
        MultipartBody.Builder mBody = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (param != null) {
            String picUrl = param.get("filedata").toString();
            File picFile = new File(picUrl);
            if (picFile.exists()) {
                mBody.addFormDataPart("pic", picFile.getName(), RequestBody.create(
                        YPE_PNG, picFile));
            }
            FormBody.Builder builder = new FormBody.Builder();
            Iterator it = param.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
                mBody.addFormDataPart("" + entry.getKey(), "" + entry.getValue());
            }
            final Request request = new Request.Builder()
                    .url(url)
                    .post(mBody.build())
                    .build();
            Call call = mClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    if (mCallBack != null) {
                        mCallBack.onFail(404, e.getMessage());
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.isSuccessful()) {
                        if (response.body() != null) {
                            try {
                                String result = readInputStream(response.body().byteStream());
                                mCallBack.onSuccess(response.code(), result);
                            } catch (IOException e) {
                                mCallBack.onFail(response.code(), response.message());
                                e.printStackTrace();
                            }


                        }
                    } else {
                        if (response != null) {
                            try {
                                String result = readInputStream(response.body().byteStream());
                                mCallBack.onSuccess(response.code(), result);
                            } catch (IOException e) {
                                mCallBack.onFail(response.code(), response.message());
                                e.printStackTrace();
                            }
                        }
                    }
                }
            });
        }


    }

    /**
     * 从输入流中读取数据
     *
     * @param inStream
     * @return
     * @throws Exception
     */
    public String readInputStream(InputStream inStream) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        String data = outStream.toString("UTF-8");
        outStream.close();
        inStream.close();
        return data;
    }


    public String propertURLStr(String url, Map<String, String> queries) throws Exception {
        return propertURL(url, queries).toString();
    }

    /**
     * 配置url 格式
     *
     * @param url
     * @param queries
     * @return
     */
    public URL propertURL(String url, Map<String, String> queries) {
        LogUtil.w("yjl", url);
        StringBuilder sb = new StringBuilder();
        URL u = null;
        sb.append(url);

        if (queries != null && queries.size() > 0) {
            if (!url.contains("?")) {
                sb.append("?");
            } else {
                sb.append("&");
            }
            for (Map.Entry<String, String> entry : queries.entrySet()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue())
                        .append("&");
            }
            sb.setLength(sb.length() - 1);
        }

        try {
            u = new URL(sb.toString());
        } catch (MalformedURLException e) {
        }

        return u;
    }

    /**
     * 使用Picasso +okhttp3 实现的图片加载
     * 也可以使用image util加载图片
     *
     * @param mContext     context
     * @param url          图片URL
     * @param view         显示图片的imageView
     * @param defaultImage 下载过程中显示的图片
     * @param failImage    下载失败显示的图片
     * @throws Exception
     */
    @Override
    public void loadImage(Context mContext, String url, ImageView view, int defaultImage, int failImage) throws Exception {
        if (!StringUtil.isUrl(url)) {
            LogUtil.e(url + " url is not available!");
            return;
        }
        if (okHttpDownLoader == null) {
            okHttpDownLoader = new OkHttpDownLoader(mClient);
        }
        if (picasso == null) {
            picasso = new Picasso.Builder(mContext)
                    .downloader(new OkHttpDownLoader(mClient))
                    .build();
            Picasso.setSingletonInstance(picasso);
        }

        RequestCreator requestCreator = Picasso.with(mContext).load(url);
        if (defaultImage > 0) {
            requestCreator.placeholder(defaultImage);
        }
        if (failImage > 0) {
            requestCreator.placeholder(failImage);
        }
        requestCreator.into(view);
//        Picasso.with(mContext)
//                //load()下载图片
//                .load(url)
//
//                //下载中显示的图片
//                .placeholder(defaultImage)
//
//                //下载失败显示的图片
//                .error(failImage)
//
//                //init()显示到指定控件
//                .into(view);

    }

    /**
     * 加载图拍，显示默认图片
     *
     * @param mContext
     * @param url
     * @param view
     * @param defaultImage
     * @throws Exception
     */
    public void loadImage(Context mContext, String url, ImageView view, int defaultImage) throws Exception {
        loadImage(mContext, url, view, defaultImage, defaultImage);
    }

    public void loadRequsetByRaw(String url, String json, final ICallBack mCallBack) throws IOException {
        LogUtil.e("yjl", "url:" + url);
        LogUtil.e("yjl", "json:" + json);
        MediaType JSON = MediaType.parse("application/raw; charset=utf-8");
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        Call call = mClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                LogUtil.e("yjl", "onFailure:" + e.getMessage());
                if (mCallBack != null) {
                    mCallBack.onFail(100000, e.getMessage());
                }
            }

            @Override
            public void onResponse(Call call, okhttp3.Response response) throws IOException {
                LogUtil.e("onResponse:" + response.message());
                if (response.isSuccessful()) {
                    if (response.body() != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }
                    }
                } else {
                    if (response != null) {
                        try {
                            String result = readInputStream(response.body().byteStream());
                            mCallBack.onSuccess(response.code(), result);
                        } catch (IOException e) {
                            mCallBack.onFail(response.code(), response.message());
                            e.printStackTrace();
                        }
                    }
                }
            }
        });

    }
}
